

#ifndef H_MM
#define H_MM

//using 75000 results in only 13 pages which is convenient for demonstration purposes
#define PAGE_SIZE 75000 //4096 //kb
#define MAIN_SIZE 1024000 //kb
#define BS_SIZE   51200000 //kb 

#define MAIN_PAGES (MAIN_SIZE / PAGE_SIZE)
#define BS_PAGES   (BS_SIZE / PAGE_SIZE)
#define N_PAGES (MAIN_PAGES + BS_PAGES) // Total number of pages

#define BS_Q_SIZE 20 // How many outstanding tasks we queue to the BS



// Page states:
typedef enum {PG_FREE, //page was never allocated to a process or the kernel
							PG_ALLOC,//page was allocated to a process but never 
											 //used/referenced yet (a page fault is necessary). 
											 //A page remains in this state until a page fault 
											 //occurs.
							PG_FAULTED, //page fault occurred and the MM has made a request 
													// to the BS to pull the bits of this page into 
													// the main memory
							PG_INMEM, // page is currently in memory being used
							PG_SWAPPING, // MM has made a request to the BS to store the
													 // bits of this page. It is still in memory and
													 // can still be used
							PG_SWAPPED // Page is swapped out to the BS.
} page_state;

struct {
	struct page_desc *head; // the least recently used page
	struct page_desc *tail; // the most recently used page
} lru_list;

struct page_desc;

struct page_table {
  // id of a page table is same as the id of the owner process
  //int page_table_id;
  int pid; // id of the owner of this page table
  int size; // how many pages in there
  int last_page_id;
  struct page_desc *head;
  struct page_desc *tail;
};

struct page_desc {
  char state;
  int page_id; // unique within the process
  // related to the page_table linked list constructs
  char is_kernel_page; // We don't swap these out...
  struct page_desc *next;
  struct page_table *owner;
  
  // for keeping track of the neighbors that were referenced before/after this page
  struct page_desc *lru_next; // a more recently used page
  struct page_desc *lru_prev; // a less recently used page
  
  int offset; // Offset of this page in the main memory or the BS.
              // If the state is free, 
  /*            
  int frame; // If this page was swapped out, what frame it is in. When state
             // is PG_SWAPPED, frame will tell what frame this page is in and
             // what offset within that frame we can find the contents of the
             // page. So, this is useful only when the state is PG_SWAPPED.
	*/
};


// PA_NONE: free (reusable) slots
// PA_STORE: page is sent to the BS
// PA_RETRIEVE: page is requested from the BS
typedef enum {PA_NONE, PA_STORE, PA_RETRIEVE} bs_action;
struct page_action {
	bs_action op;
	int source_offset;
	int target_offset;
	struct page_desc *subject;
	struct page_action *next; // in the queue
};

struct bs_queue_definition {
	int n_elements;
	int next_free;
	struct page_action *head;
	struct page_action *tail;
	struct page_action page_actions[BS_Q_SIZE];
};
struct bs_queue_definition bs_queue;

// Function signatures
int init_mm();
int alloc_pt(struct page_table* pt, int pid, int n_pages);
#include <pm.h>
void dealloc_pt(struct process *proc);
int handle_page_fault(struct process* proc, int page_num);
int bs_interrupt();
int get_mm_size();
struct page_desc* get_page(struct process* p, int pg_id);
int use_page(struct process* proc, int page_id);



#endif // H_MM
